package com.kgcx.schedule.service;

import com.kgcx.common.client.organization.pojo.Driver;
import com.kgcx.common.constant.Cons;
import com.kgcx.common.constant.ErrorCode;
import com.kgcx.core.exception.BusinessException;
import com.kgcx.core.utils.HelpUtil;
import com.kgcx.schedule.client.City;
import com.kgcx.schedule.domain.ScheduleRecordDomain;
import com.kgcx.schedule.domain.ScheduleReserveCfgDetailDomain;
import com.kgcx.schedule.model.OptionallyBook;
import com.kgcx.schedule.model.ScheduleException;
import com.kgcx.schedule.model.ScheduleRound;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.util.Calendar;
import java.util.List;
import java.util.Map;

/**
 * 预约用车
 *
 * @author 袁进勇
 */
@Service
public class SchedulePlanCommonOrderService extends ScheduleOrderBookService {
    private static final Logger LOG = LoggerFactory.getLogger(SchedulePlanCommonOrderService.class);

    private OptionallyBook setting = null;

    @Override
    protected Timestamp calculateScheduleTime(ScheduleRecordDomain record) {
        OptionallyBook setting = scheduleSettingsService.getSetting(record.getCity_id(), OptionallyBook.class);
        return HelpUtil.addTime(record.getPlan_depart_time(), Calendar.MINUTE, 0 - setting.getMin_time());
    }

    @Override
    protected Timestamp getMinTime(ScheduleRecordDomain record) {
        OptionallyBook setting = getScheduleSetting(record.getCity_id());
        return HelpUtil.addTime(record.getCreate_time(), Calendar.MINUTE, setting.getMin_time());
    }

    @Override
    protected Timestamp getMaxTime(ScheduleRecordDomain record) {
        OptionallyBook setting = getScheduleSetting(record.getCity_id());
        return HelpUtil.addTime(record.getCreate_time(), Calendar.DAY_OF_MONTH, setting.getMin_time());
    }

    @Override
    protected void checkRecord(ScheduleRecordDomain record, ScheduleReserveCfgDetailDomain cfgDetail)
            throws ScheduleException {
        // 可预约最短时间检查
        Timestamp minTime = getMinTime(record);
        if (minTime.after(record.getPlan_depart_time())) {
            LOG.warn(String.format("订单[%s]，用车时间[%s]小于可预约最短时间[%s]，下单失败！", record.getOrder_no(),
                    HelpUtil.formatDatetime(record.getPlan_depart_time()), HelpUtil.formatDatetime(minTime)));
            throw new ScheduleException(ErrorCode.SCHEDULE_DEPART_LT_MIN, "用车时间必须大于可预约最短时间！");
        }

        super.checkRecord(record, cfgDetail);
    }

    @Override
    protected Driver chooseDriver(ScheduleRecordDomain record, Map<Integer, List<Driver>> driverMap) {
        LOG.info(String.format("订单[%s]，调度车辆/司机。", record.getOrder_no()));

        // 1、场外在线车辆派单
        Driver driver = chooseStateOnDriver(record, driverMap);
        if (driver != null) {
            LOG.info(String.format("订单[%s]，找到符合调度规则的场外在线车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                    driver.getAutoId(), driver.getKid()));
            return driver;
        }

        // 2、有待命车辆时，按待命排队顺序调度
        driver = chooseStateStayDriver(record, driverMap);
        if (driver != null) {
            LOG.info(String.format("订单[%s]，找到符合调度规则的待命车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                    driver.getAutoId(), driver.getKid()));
            return driver;
        }

        // 3、有入栈中车辆时，按入栈中状态变更顺序调度
        driver = chooseStatePreInDriver(record, driverMap);
        if (driver != null) {
            LOG.info(String.format("订单[%s]，找到符合调度规则的入栈中车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                    driver.getAutoId(), driver.getKid()));
            return driver;
        }

        // 4、有入栈车辆时，按入栈排队顺序调度
        driver = chooseStateInDriver(record, driverMap);
        if (driver != null) {
            LOG.info(String.format("订单[%s]，找到符合调度规则的入栈车辆/司机，车辆ID[%d]，司机ID[%d]。", record.getOrder_no(),
                    driver.getAutoId(), driver.getKid()));
            return driver;
        }

        return null;
    }

    @Override
    protected ScheduleRound getScheduleRound(ScheduleRecordDomain record) {
        OptionallyBook setting = getScheduleSetting(record.getCity_id());
        List<ScheduleRound> rounds = setting.getRounds();
        if (!HelpUtil.isEmpty(rounds) && rounds.size() > record.getSchedule_count()) {
            return rounds.get(record.getSchedule_count());
        }

        return null;
    }

    @Override
    protected void scheduleSuccessful(ScheduleRecordDomain record, Driver driver) {
        // 更新推送司机信息给乘客的时间，改派司机后，需要设置推送时间和状态
        updateNotifyTime(record,
                HelpUtil.addTime(record.getPlan_depart_time(), Calendar.MINUTE, 0 - setting.getNotify_time()));

        // 短信通知下单人
        OptionallyBook setting = getScheduleSetting(record.getCity_id());
        String placingUserPhone = record.getPlacing_user_phone();
        if (Cons.$true(setting.getIs_send_msg())) { // 短信发送开关打开
            sendSuccessfulMSG(placingUserPhone, setting.getMsg_id(), record);
        }

        // 给别人叫车时，检查是否短信通知乘车人
        String passengerPhone = record.getPassenger_phone();
        if (Cons.$true(record.getIs_msg_passenger())
                && (!HelpUtil.isEmpty(passengerPhone) && !passengerPhone.equals(placingUserPhone))) {
            sendSuccessfulMSG(passengerPhone, setting.getMsg_id(), record);
        }
    }

    private OptionallyBook getScheduleSetting(Long cityId) {
        return scheduleSettingsService.getSetting(cityId, OptionallyBook.class);
    }

    @Override
    protected String getAdminPhone(ScheduleRecordDomain record) {
        City city = cityClient.getCity(record.getCity_id());
        if (city != null) {
            return city.getManagerPhone();
        }

        LOG.error(String.format("获取城市[%d]信息失败，城市不存在！", record.getCity_id()));
        throw new BusinessException(1L, "获取城市[" + record.getCity_id() + "]信息失败，城市不存在！");
    }
}
